package com.googlecode.grt192.HH11.actuator;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;

import com.googlecode.grtframework.vis.Displayable;
import com.googlecode.grtframework.vis.IMountedPosition;
import com.googlecode.grtframework.vis.Mountable;

/**
 * Simulates a pneumatic actuator, as abstracted with a solenoid valve
 * 
 * @author ajc
 * 
 */
public class PneumaticActuatorDisplay extends Thread implements ISolenoid,
		Displayable, Mountable {

	/**
	 * Time constants
	 */
	private static final double MS_PER_SEC = 1000;
	private static final int TIMESTEP = 50; // milliseconds
	private static final double TIMESTEP_SECS = TIMESTEP / MS_PER_SEC; // seconds

	/*
	 * Dimensions
	 */
	private final int actuatorLength;
	private final int boreLength;
	private final int actuatorWidth;
	private final int boreWidth;
	private final int rodYOffset;

	// rod motion
	private int rodExtensionTarget;
	private double rodExtension;

	private final IMountedPosition pos;
	private final String name;

	private boolean running;

	// Timings
	private final double contractTime; // time it takes to contract
	private final double retractTime;// time it takes to retract
	private final boolean defaultContract; // true if inactive (off) state is

	// contracted

	/**
	 * Constructs a customizable actuator
	 * 
	 * @param pos
	 *            GUI position
	 * @param name
	 *            name label of actuator
	 * @param length
	 *            GUI length of actuator
	 * @param width
	 *            GUI width of actuator
	 * @param rodLength
	 *            GUI length of actuator rod
	 * @param contractTime
	 *            time(s) taken for actuator to contract
	 * @param retractTime
	 *            time(s) taken for actuator to retract
	 * @param defaultContract
	 *            true if solenoid off is contracted
	 * 
	 */
	public PneumaticActuatorDisplay(IMountedPosition pos, String name,
			int length, int width, int rodLength, double contractTime,
			double retractTime, boolean defaultContract) {
		this.pos = pos;
		this.name = name;
		this.actuatorLength = length;
		this.actuatorWidth = width;
		this.boreLength = rodLength;
		this.contractTime = contractTime;
		this.retractTime = retractTime;
		this.defaultContract = defaultContract;
		rodExtension = defaultContract ? 0 : boreLength;
		boreWidth = width / 4;
		rodYOffset = (width - boreWidth) / 2;
	}

	@Override
	public void deactivate() {
		// when solenoid inactive(off):
		// extensionTarget is 0 if we are default contract
		// full length if we are default retract
		rodExtensionTarget = defaultContract ? 0 : boreLength;
	}

	@Override
	public void activate() {
		// when solenoid active(on):
		// extensionTarget is full length if we are default contract
		// 0 if we are default retract
		rodExtensionTarget = defaultContract ? boreLength : 0;
	}

	public void run() {
		running = true;
		while (running) {
			/*
			 * adjust position at a constant velocity
			 */
			if (rodExtension < rodExtensionTarget) {// we are retracting
				rodExtension += TIMESTEP_SECS * boreLength / retractTime;
			} else if (rodExtension > rodExtensionTarget) {// we are contracting
				rodExtension -= TIMESTEP_SECS * boreLength / contractTime;
			}

			try {
				Thread.sleep(TIMESTEP);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	@Override
	public void display(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;

		// rotate to trueHeading with respect to absolute 2d orientation and
		// position
		AffineTransform orig = g2.getTransform();
		AffineTransform newRotation = new AffineTransform();
		newRotation.rotate(getHeading(), getX(), getY());
		g2.setTransform(newRotation);

		// TODO mounted position at end of actuator
		// TODO pivoting
		// TODO Fittings?

		// rod
		g.setColor(Color.DARK_GRAY);
		g.fillRect((getX() + (int) rodExtension), getY() + rodYOffset,
				actuatorLength, boreWidth);

		// cylinder
		g.setColor(Color.gray);
		g.fillRect(getX(), getY(), actuatorLength, actuatorWidth);

		// name
		g.setColor(Color.DARK_GRAY);
		g.drawString(name, getX(), getY() + 15);

		// unrotate
		g2.setTransform(orig);
	}

	@Override
	public double getHeading() {
		return pos.getHeading();
	}

	@Override
	public int getX() {
		return pos.getX();
	}

	@Override
	public int getY() {
		return pos.getY();
	}

}
